package com.grandtech.insurance.common.utils;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import org.apache.http.util.TextUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;

/**
 * 照片添加水印
 * Created by ren on 2020/8/21
 */
public class WaterMarkUtil {
    // 水印透明度
    private static float alpha = 0.3f;
    // 水印横向位置
    private static int positionWidth = 50;
    // 水印纵向位置
    private static int positionHeight = 100;
    // 水印文字字体
    private static Font font = new Font("宋体", Font.BOLD, 20);
    // 水印文字颜色
    private static Color color = Color.red;

    /**
     * 给图片添加水印文字
     *
     * @param text       水印文字
     * @param srcImgPath 源图片路径
     * @param targetPath 目标图片路径
     */
    public static void markImage(String text, String srcImgPath, String targetPath) {
        markImage(text, srcImgPath, targetPath, null);
    }

    /**
     * 给图片添加水印文字
     *
     * @param srcImgFile         源图片路径
     * @param targetImgFile      目标图片路径
     * @param markTextArr        水印文字
     */
    public static void markImage(MultipartFile srcImgFile, File targetImgFile, String[] markTextArr) {
        // 获取上传的文件名称
        String originalFilename = srcImgFile.getOriginalFilename();
        if (TextUtils.isEmpty(originalFilename)) {
            return;
        }
        // 获取文件类型 jpg
        String fileType = "";
        if (originalFilename.contains(".")) {
            fileType = originalFilename.substring(originalFilename.lastIndexOf(".") + 1, originalFilename.length());
        } else {
            fileType = "png";
        }
        font = new Font("宋体", Font.BOLD, 18);
        color = Color.white;
        alpha = 1.0f;
        try {
            InputStream inputStream = srcImgFile.getInputStream();
            OutputStream outputStream = new FileOutputStream(targetImgFile);

            // 判断是否有警告信息
            /*boolean mHasWarning = warningTextArr != null && warningTextArr.length > 0;
            if (!mHasWarning) {
                // io流 添加水印
                markImageByIo(inputStream, outputStream, 0, fileType, markTextArr);
            } else {*/
                // io流 添加水印，警告

                // 获取警告logo图片流
               /* InputStream warningLogoInputStream = warningLogoImgFile != null ? warningLogoImgFile.getInputStream() :
                        WaterMarkUtil.class.getClassLoader().getResourceAsStream("static/warn.png");
                */markImageByIo(inputStream, outputStream, 0, fileType, markTextArr);
            //}
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    //=================================添加水印 具体实现========================================================================

    /**
     * 给图片添加水印文字、可设置水印文字的旋转角度
     *
     * @param markText
     * @param srcImgPath
     * @param targetPath
     * @param degree
     */
    public static void markImage(String markText, String srcImgPath, String targetPath, Integer degree) {

        OutputStream os = null;
        try {
            // 0、图片类型
            String type = srcImgPath.substring(srcImgPath.indexOf(".") + 1, srcImgPath.length());

            // 1、源图片
            Image srcImg = ImageIO.read(new File(srcImgPath));

            int imgWidth = srcImg.getWidth(null);
            int imgHeight = srcImg.getHeight(null);

            BufferedImage buffImg = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);

            // 2、得到画笔对象
            Graphics2D g = buffImg.createGraphics();
            // 3、设置对线段的锯齿状边缘处理
            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g.drawImage(srcImg.getScaledInstance(imgWidth, imgHeight, Image.SCALE_SMOOTH), 0, 0, null);
            // 4、设置水印旋转
            if (null != degree) {
                g.rotate(Math.toRadians(degree), (double) buffImg.getWidth() / 2, (double) buffImg.getHeight() / 2);
            }
            // 5、设置水印文字颜色
            g.setColor(color);
            // 6、设置水印文字Font
            g.setFont(font);
            // 7、设置水印文字透明度
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
            // 8、第一参数->设置的内容，后面两个参数->文字在图片上的坐标位置(x,y)

            g.drawString(markText, positionWidth, positionHeight);
            // 9、释放资源
            g.dispose();
            // 10、生成图片
            os = new FileOutputStream(targetPath);
            // ImageIO.write(buffImg, "JPG", os);
            ImageIO.write(buffImg, type.toUpperCase(), os);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != os)
                    os.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 给图片添加水印文字、可设置水印文字的旋转角度
     *
     * @param inputStream
     * @param outputStream
     * @param degree
     * @param typeName
     * @param markTextArr
     */
    private static void markImageByIo(InputStream inputStream,
                                      OutputStream outputStream,
                                      Integer degree,
                                      String typeName,
                                      String... markTextArr) {
        try {
            // 1、源图片
            Image srcImg = ImageIO.read(inputStream);

            int imgWidth = srcImg.getWidth(null);
            int imgHeight = srcImg.getHeight(null);
            BufferedImage buffImg = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);

            // 设置字体，设置两倍水印行数，预留超出宽度换行
            setMarkFont(imgHeight, markTextArr.length * 2);

            // 2、得到画笔对象
            Graphics2D g = buffImg.createGraphics();
            // 3、设置对线段的锯齿状边缘处理
            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g.drawImage(srcImg.getScaledInstance(imgWidth, imgHeight, Image.SCALE_SMOOTH), 0, 0, null);
            // 4、设置水印旋转
            if (null != degree) {
                g.rotate(Math.toRadians(degree), (double) buffImg.getWidth() / 2, (double) buffImg.getHeight() / 2);
            }
            // 5、设置水印文字颜色
            g.setColor(color);
            // 6、设置水印文字Font
            g.setFont(font);
            // 7、设置水印文字透明度
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));

            // 测量文字的高度
            FontMetrics mMetrics = new JLabel().getFontMetrics(font);
            int mFontHeight = mMetrics.getHeight();

            // 设置水印距照片边缘的距离
            int markPaddingLeft = mFontHeight / 2;
            int markPaddingBottom = mFontHeight / 2;
            // 截取水印文字，适应图片宽度
            markTextArr = splitMarkStrAdaptImgWidth(imgWidth - markPaddingLeft * 2, markTextArr);
            int markPaddingTop = imgHeight - markPaddingBottom - (mFontHeight * markTextArr.length);

            // 8、第一参数->设置的内容，后面两个参数->文字在图片上的坐标位置(x,y)
            for (int i = 0; i < markTextArr.length; i++) {
                String markStr = markTextArr[i];
                JLabel label = new JLabel(markStr);
                FontMetrics metrics = label.getFontMetrics(font);
                int markWidth = metrics.stringWidth(label.getText());//文字水印的宽
                int markHegiht = metrics.getHeight();
                positionWidth = markPaddingLeft;
                positionHeight = markPaddingTop + mFontHeight * i;
                g.drawString(markStr, positionWidth, positionHeight + mFontHeight);// 文字起点是从文字左下角计算，向上绘制
            }

            // 9、释放资源
            g.dispose();
            // 10、生成图片，size会比原图小
//            ImageIO.write(buffImg, typeName.toUpperCase(), outputStream);

            // 生成高质量图片
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(outputStream);
            JPEGEncodeParam jep = JPEGCodec.getDefaultJPEGEncodeParam(buffImg);
            jep.setQuality(0.9f, true);
            encoder.encode(buffImg, jep);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 给图片添加水印文字、可设置水印文字的旋转角度
     * (添加警告文字)
     *
     * @param inputStream
     * @param outputStream
     * @param degree
     * @param typeName
     * @param markTextArr            水印文字
     * @param warningTextArr         警告文字
     * @param warningLogoInputStream 警告logo图片流
     */
    private static void markImageByIo(InputStream inputStream,
                                      OutputStream outputStream,
                                      Integer degree,
                                      String typeName,
                                      String[] markTextArr,
                                      String[] warningTextArr,
                                      InputStream warningLogoInputStream) {
        try {
            // 1、源图片
            Image srcImg = ImageIO.read(inputStream);

            int imgWidth = srcImg.getWidth(null);
            int imgHeight = srcImg.getHeight(null);
            BufferedImage buffImg = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);

            // 设置字体，设置两倍水印行数，预留超出宽度换行
            setMarkFont(imgHeight, (markTextArr.length + warningTextArr.length) * 2);

            // 2、得到画笔对象
            Graphics2D g = buffImg.createGraphics();
            // 3、设置对线段的锯齿状边缘处理
            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g.drawImage(srcImg.getScaledInstance(imgWidth, imgHeight, Image.SCALE_SMOOTH), 0, 0, null);
            // 4、设置水印旋转
            if (null != degree) {
                g.rotate(Math.toRadians(degree), (double) buffImg.getWidth() / 2, (double) buffImg.getHeight() / 2);
            }
            // 测量文字的高度
            FontMetrics mMetrics = new JLabel().getFontMetrics(font);
            int mFontHeight = mMetrics.getHeight();

            // 下个水印开始绘制的高度位置（默认从原图片底部开始）
            int mNextMarkViewStartHeight = imgHeight;

            // 判断是否有警告
            boolean mHasWarning = warningTextArr != null && warningTextArr.length > 0;

            // =======================添加警告=============================
            if (mHasWarning) {
                // 5、设置水印文字颜色
                g.setColor(Color.RED);
                // 6、设置水印文字Font
                g.setFont(font);
                // 7、设置水印文字透明度
                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));


                // 8、第一参数->设置的内容，后面两个参数->文字在图片上的坐标位置(x,y)
                // 获取warnLogoImage
                Image mWarnLogoImg = null;
                int mWarnLogoImgWidth = 0;
                int mWarnLogoImgHeight = 0;
                if (warningLogoInputStream != null) {
                    mWarnLogoImg = ImageIO.read(warningLogoInputStream);
                    mWarnLogoImgWidth = mWarnLogoImg.getWidth(null);
                    mWarnLogoImgHeight = mWarnLogoImg.getHeight(null);
                }
                // 计算警告的每行高度
                int mWarnLineHeight = mWarnLogoImgHeight > mFontHeight ? mWarnLogoImgHeight : mFontHeight;
                // 设置行间距
                int mLineMargin = 5;
                // 设置水印距照片边缘的距离
                int warningPaddingLeft = mFontHeight / 2;
                int warningPaddingBottom = mFontHeight / 2;

                // 截取水印文字，适应图片宽度
                warningTextArr = splitMarkStrAdaptImgWidth(imgWidth - warningPaddingLeft * 2, warningTextArr);
                int warningPaddingTop = mNextMarkViewStartHeight < imgHeight ?
                        mNextMarkViewStartHeight - warningPaddingBottom - (mWarnLineHeight * warningTextArr.length) - (mLineMargin * warningTextArr.length - 1) :
                        imgHeight - warningPaddingBottom - (mWarnLineHeight * warningTextArr.length) - (mLineMargin * warningTextArr.length - 1);

                mNextMarkViewStartHeight = warningPaddingTop;

                for (int i = 0; i < warningTextArr.length; i++) {
                    positionWidth = warningPaddingLeft;
                    positionHeight = warningPaddingTop + (mWarnLineHeight + mLineMargin) * i;

                    // 加载warnLogo
                    if (mWarnLogoImg != null) {
                        g.drawImage(mWarnLogoImg, positionWidth, positionHeight, mWarnLogoImgWidth, mWarnLogoImgHeight, null);
                    }

                    // 加载warnStr
                    String warningStr = warningTextArr[i];
                    JLabel label = new JLabel(warningStr);
                    FontMetrics metrics = label.getFontMetrics(font);
                    int markWidth = metrics.stringWidth(label.getText());//文字水印的宽
                    int markHegiht = metrics.getHeight();
                    positionWidth = warningPaddingLeft + (mWarnLogoImgWidth + mLineMargin);
                    positionHeight = positionHeight + (mWarnLogoImgHeight - mFontHeight) / 2 - (metrics.getLeading() * 2);// 垂直居中显示文字，减去文字行距
                    g.drawString(warningStr, positionWidth, positionHeight + mFontHeight);// 文字起点是从文字左下角计算，向上绘制
                }
            }

            // =======================添加水印=============================
            // 5、设置水印文字颜色
            g.setColor(color);
            // 6、设置水印文字Font
            g.setFont(font);
            // 7、设置水印文字透明度
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));

            // 8、第一参数->设置的内容，后面两个参数->文字在图片上的坐标位置(x,y)

            // 设置水印距照片边缘的距离
            int markPaddingLeft = mFontHeight / 2;
            int markPaddingBottom = mFontHeight / 2;
            // 截取水印文字，适应图片宽度
            markTextArr = splitMarkStrAdaptImgWidth(imgWidth - markPaddingLeft * 2, markTextArr);

            int markPaddingTop = mNextMarkViewStartHeight < imgHeight ?
                    mNextMarkViewStartHeight - markPaddingBottom - (mFontHeight * markTextArr.length) :
                    imgHeight - markPaddingBottom - (mFontHeight * markTextArr.length);

            for (int i = 0; i < markTextArr.length; i++) {
                String markStr = markTextArr[i];
                JLabel label = new JLabel(markStr);
                FontMetrics metrics = label.getFontMetrics(font);
                int markWidth = metrics.stringWidth(label.getText());//文字水印的宽
                int markHegiht = metrics.getHeight();
                positionWidth = markPaddingLeft;
                positionHeight = markPaddingTop + mFontHeight * i;
                g.drawString(markStr, positionWidth, positionHeight + mFontHeight);// 文字起点是从文字左下角计算，向上绘制
            }


            // 9、释放资源
            g.dispose();
            // 10、生成图片，size会比原图小
//            ImageIO.write(buffImg, typeName.toUpperCase(), outputStream);

            // 生成高质量图片
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(outputStream);
            JPEGEncodeParam jep = JPEGCodec.getDefaultJPEGEncodeParam(buffImg);
            jep.setQuality(0.9f, true);
            encoder.encode(buffImg, jep);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 设置水印字体
     *
     * @param imgHeight 图片高度
     * @param markLines 水印文字行数
     */
    private static void setMarkFont(int imgHeight, int markLines) {
        // 水印区最大高度
        int markViewHeightMax = imgHeight / 4;

        int fontSize = 18;
        int fontHeight = new JLabel().getFontMetrics(new Font("宋体", Font.BOLD, fontSize)).getHeight();
        int markViewHeight = fontHeight * markLines;
        while (markViewHeight < markViewHeightMax) {
            fontSize++;
            fontHeight = new JLabel().getFontMetrics(new Font("宋体", Font.BOLD, fontSize)).getHeight();
            markViewHeight = fontHeight * markLines;
        }
        font = new Font("宋体", Font.BOLD, fontSize);
    }

    /**
     * 截取水印文字适配图片宽度
     *
     * @param imgWidth    图片宽度
     * @param markTextArr 水印文字
     */
    private static String[] splitMarkStrAdaptImgWidth(int imgWidth, String... markTextArr) {
        ArrayList<String> markTextList = new ArrayList<>();

        JLabel label = new JLabel();
        FontMetrics metrics = label.getFontMetrics(font);

        for (String markStr :
                markTextArr) {
            // 循环截取水印文字
            String mRestStr = markStr;
            boolean mHasRest = true;
            while (mHasRest) {
                for (int j = mRestStr.length(); j > 1; j--) {
                    int width = metrics.getStringBounds(mRestStr, 0, j, label.getGraphics()).getBounds().width;
                    if (width < imgWidth) {
                        // 获取适配的文字，放到集合中
                        String adapterStr = mRestStr.substring(0, j);
                        markTextList.add(adapterStr);

                        // 计算剩余文字宽度
                        mRestStr = mRestStr.substring(j);
                        int restWidth = metrics.getStringBounds(mRestStr, 0, mRestStr.length(), label.getGraphics()).getBounds().width;
                        // 跳出循环
                        if (restWidth < imgWidth) {
                            mHasRest = false;
                            if (!TextUtils.isBlank(mRestStr)) {
                                markTextList.add(mRestStr);
                            }
                        }
                        break;
                    }
                }
            }
        }
        return markTextList.toArray(new String[]{});
    }

    public static void addMark2(InputStream inputStream, OutputStream outputStream) {
        try {
//            // 获取图片后缀
//            if(imageUrl.indexOf(".") > -1) {
//                suffix = imageUrl.substring(imageUrl.lastIndexOf(".") + 1);
//            }
//            Image img = ImageIO.read(url);

            // 1、源图片
            Image srcImg = ImageIO.read(inputStream);

            Font font = new Font("宋体", Font.BOLD, 15);
            Color markContentColor = Color.GRAY;
            int srcImgWidth = srcImg.getWidth(null);//获取图片的宽
            int srcImgHeight = srcImg.getHeight(null);//获取图片的高
            // 加水印
            BufferedImage bufImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB);
            Graphics2D g = bufImg.createGraphics();//得到画笔
            g.drawImage(srcImg, 0, 0, srcImgWidth, srcImgHeight, null);
            g.setColor(markContentColor); //设置水印颜色
            g.setFont(font);              //设置字体
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.6f));//设置水印文字透明度
            g.rotate(Math.toRadians(-45), (double) bufImg.getWidth(), (double) bufImg.getHeight());//设置水印旋转
            JLabel label = new JLabel("哈哈哈哈");
            FontMetrics metrics = label.getFontMetrics(font);
            int width = metrics.stringWidth(label.getText());//文字水印的宽
            int rowsNumber = srcImgHeight / width + srcImgHeight % width;// 图片的高  除以  文字水印的宽  打印的行数(以文字水印的宽为间隔)
            int columnsNumber = srcImgWidth / width + srcImgWidth % width;//图片的宽 除以 文字水印的宽  每行打印的列数(以文字水印的宽为间隔)
            //防止图片太小而文字水印太长，所以至少打印一次
            if (rowsNumber < 1) {
                rowsNumber = 1;
            }
            if (columnsNumber < 1) {
                columnsNumber = 1;
            }
            for (int j = 0; j < rowsNumber; j++) {
                for (int i = 0; i < columnsNumber; i++) {
                    g.drawString("哈哈哈哈", i * width + j * width, -i * width + j * width);//画出水印,并设置水印位置
                }
            }
            g.dispose();// 释放资源
            // 输出图片
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(baos);
            ImageIO.write(bufImg, "png", imageOutputStream);

            outputStream.write(baos.toByteArray());
            outputStream.flush();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
